{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "Lesson 3 - Матрицы и матричные операции, Часть 1.ipynb",
      "provenance": [],
      "collapsed_sections": []
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.7.1"
    },
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "HPMpEWusIIIM"
      },
      "source": [
        "# Урок 3"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "USFuS5Q1IIIP"
      },
      "source": [
        "## Матрицы и матричные операции. Часть 1"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "TMasMmypIIIQ"
      },
      "source": [
        "__Матрицей__ размера $m\\times n$ называется прямоугольная таблица, состоящая из $m$ строк и $n$ столбцов. Элементы матрицы, обозначаемой заглавной буквой (например $A$), обычно обозначаются $a_{ij}$, где индексы $i$ и $j$ — соответственно номера строки и столбца, в которых находится элемент. \n",
        "\n",
        "$$\\begin{pmatrix}\n",
        "a_{11} & a_{12} & \\cdots & a_{1n}\\\\ \n",
        "a_{21} & a_{22} & \\cdots & a_{2n}\\\\  \n",
        "\\cdots & \\cdots & \\ddots & \\cdots \\\\ \n",
        "a_{m1} & a_{m2} & \\cdots & a_{mn}\\\\ \n",
        "\\end{pmatrix}$$\n",
        "\n",
        "Числа $m$ и $n$ называют _порядками_ матрицы. Если $m=n$, то матрица называется _квадратной_, а число $m=n$ — ее _порядком_.\n",
        "\n",
        "Для краткого обозначения матрицы иногда используется символ $\\left\\|a_{ij}\\right\\|$ или выражение $A = \\left\\|a_{ij}\\right\\| = (a_{ij}) ~ (i = 1,2,...,m; ~ j = 1,2,...,n).$"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "RwRqbRk2IIIS"
      },
      "source": [
        "В машинном обучении матрицы обычно используются для хранения информации об объектах и их признаках. При этом обычно по строкам распологаются объекты, а по столбцам — признаки (некоторые свойства объектов, значения которых используются для обучения модели и которые затем эта модель должна предсказывать для других объектов)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "_s1EMY5hIIIT"
      },
      "source": [
        "Векторы, изученные в предыдущих уроках, являются частными случаями матриц: в частности, упомянутые в предыдущем уроке _вектор-строка_ (матрица размера $1\\times m$) и _вектор-столбец_ (матрица размера $n\\times1$):\n",
        "\n",
        "$$\\begin{pmatrix}\n",
        "1 & 2 & 3\n",
        "\\end{pmatrix} ~ и ~ \\begin{pmatrix}\n",
        "1\\\\ \n",
        "2\\\\ \n",
        "3\n",
        "\\end{pmatrix}.$$"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "gnbUXphsIIIV"
      },
      "source": [
        "В Python работа с матрицами обычно ведется при помощи библиотеки NumPy."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "TraIV1atIIIX"
      },
      "source": [
        "import numpy as np"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "omoiTXIqIIIf"
      },
      "source": [
        "Самый простой способ создать матрицу — с помощью функции `numpy.array(list, dtype=None, ...)`. Здесь `list` — список итерируемых объектов, которые составят строки матрицы. Мы уже использовали эту функцию в первом уроке для создания векторов (частный одномерный случай матриц)."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "IlIRX0DCIIIg",
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "outputId": "5a7d6bd8-2ddb-40b7-9c71-52311c9558e3"
      },
      "source": [
        "a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])\n",
        "print(f'Матрица:\\n{a}')"
      ],
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Матрица:\n",
            "[[1 2 3]\n",
            " [4 5 6]\n",
            " [7 8 9]]\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ww2syeCzIIIr"
      },
      "source": [
        "## Матричные операции"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "MI0lpYyYIIIs"
      },
      "source": [
        "### 1. Сложение матриц"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "lEtD1rBcIIIt"
      },
      "source": [
        "Рассмотрим матрицы $A$ размера $m\\times n$, состоящую из элементов $a_{ij}$, и $B$ того же размера, состоящую из элементов $b_{ij}$.\n",
        "\n",
        "Складывать можно только __матрицы одинаковых порядков__, и сложение их происходит поэлементно, то есть _суммой_ двух матриц $A+B$ будет являться матрица $C$ того же размера, состоящая из элементов $c_{ij}=a_{ij}+b_{ij}$:\n",
        "\n",
        "$$A + B = \n",
        "\\begin{pmatrix}\n",
        "a_{11} & a_{12} & \\cdots & a_{1n}\\\\ \n",
        "a_{21} & a_{22} & \\cdots & a_{2n}\\\\  \n",
        "\\cdots & \\cdots & \\ddots & \\cdots \\\\ \n",
        "a_{m1} & a_{m2} & \\cdots & a_{mn}\\\\ \n",
        "\\end{pmatrix} + \\begin{pmatrix}\n",
        "b_{11} & b_{12} & \\cdots & b_{1n}\\\\ \n",
        "b_{21} & b_{22} & \\cdots & b_{2n}\\\\  \n",
        "\\cdots & \\cdots & \\ddots & \\cdots \\\\ \n",
        "b_{m1} & b_{m2} & \\cdots & b_{mn}\\\\ \n",
        "\\end{pmatrix} = \\begin{pmatrix}\n",
        "a_{11} + b_{11} & a_{12} + b_{12} & \\cdots & a_{1n} + b_{1n}\\\\ \n",
        "a_{21} + b_{21}& a_{22} + b_{22}& \\cdots & a_{2n} + b_{2n}\\\\  \n",
        "\\cdots & \\cdots & \\ddots & \\cdots \\\\ \n",
        "a_{m1} + b_{m1} & a_{m2} + b_{m2} & \\cdots & a_{mn} + b_{mn}\\\\ \n",
        "\\end{pmatrix}\n",
        "= C.$$"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "jAWeBI35IIIv"
      },
      "source": [
        "__Пример__\n",
        "\n",
        "Сложим две матрицы, заполненные натуральными числами:\n",
        "\n",
        "$$\\begin{pmatrix}\n",
        "1 & 2 & 3\\\\ \n",
        "4 & 5 & 6\\\\ \n",
        "7 & 8 & 9\n",
        "\\end{pmatrix} + \\begin{pmatrix}\n",
        "1 & 1 & 1\\\\ \n",
        "1 & 1 & 1\\\\ \n",
        "1 & 1 & 1\n",
        "\\end{pmatrix} = \\begin{pmatrix}\n",
        "2 & 3 & 4\\\\ \n",
        "5 & 6 & 7\\\\ \n",
        "8 & 9 & 10\n",
        "\\end{pmatrix}.$$\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "xhSMidcRIIIx"
      },
      "source": [
        "И проведем ту же операцию при помощи Python:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "8LzN5ls4IIIz",
        "outputId": "af68fe78-1914-4982-b42b-500f9c3d718b"
      },
      "source": [
        "a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])\n",
        "b = np.ones((3,3))  # функция для создания матрицы размера (x,y), заполненной единицами\n",
        "\n",
        "print(f'Матрица A\\n{a}\\n')\n",
        "print(f'Матрица B\\n{b}\\n')\n",
        "print(f'Матрица С = A + B\\n{a + b}')"
      ],
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Матрица A\n",
            "[[1 2 3]\n",
            " [4 5 6]\n",
            " [7 8 9]]\n",
            "\n",
            "Матрица B\n",
            "[[1. 1. 1.]\n",
            " [1. 1. 1.]\n",
            " [1. 1. 1.]]\n",
            "\n",
            "Матрица С = A + B\n",
            "[[ 2.  3.  4.]\n",
            " [ 5.  6.  7.]\n",
            " [ 8.  9. 10.]]\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "x5eVeqZqIII6"
      },
      "source": [
        "Операция сложения матриц обладает теми же свойствами, что и операция сложения вещественных чисел, а именно:<br>\n",
        "1) переместительным свойством: $A+B=B+A;$<br>\n",
        "2) сочетательным свойством: $(A+B)+C=A+(B+C).$"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "erTcsjpxIII8"
      },
      "source": [
        "### 2. Умножение матриц на число"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "oGruD5fbIII9"
      },
      "source": [
        "Умножение матрицы на число происходит так же просто, как и сложение: _произведением матрицы_ $A=\\left\\|a_{ij}\\right\\|$ на число $\\lambda$ является матрица $C = \\left\\|c_{ij}\\right\\|$, элементы которой $c_{ij}=\\lambda a_{ij}$, то есть каждый элемент матрицы умножается на число $\\lambda$:\n",
        "\n",
        "$$\\lambda\\cdot\\begin{pmatrix}\n",
        "a_{11} & a_{12} & \\cdots & a_{1n}\\\\ \n",
        "a_{21} & a_{22} & \\cdots & a_{2n}\\\\  \n",
        "\\cdots & \\cdots & \\ddots & \\cdots \\\\ \n",
        "a_{m1} & a_{m2} & \\cdots & a_{mn}\\\\ \n",
        "\\end{pmatrix}=\n",
        "\\begin{pmatrix}\n",
        "\\lambda a_{11} & \\lambda a_{12} & \\cdots & \\lambda a_{1n}\\\\ \n",
        "\\lambda a_{21} & \\lambda a_{22} & \\cdots & \\lambda a_{2n}\\\\  \n",
        "\\cdots & \\cdots & \\ddots & \\cdots \\\\ \n",
        "\\lambda a_{m1} & \\lambda a_{m2} & \\cdots & \\lambda a_{mn}\\\\ \n",
        "\\end{pmatrix}.$$"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "8k-HbF3lIII-"
      },
      "source": [
        "__Пример__\n",
        "\n",
        "$$3\\cdot\\begin{pmatrix}\n",
        "1 & 2 & 3\\\\ \n",
        "4 & 5 & 6\\\\ \n",
        "7 & 8 & 9\n",
        "\\end{pmatrix} = \\begin{pmatrix}\n",
        "3 & 6 & 9\\\\ \n",
        "12 & 15 & 18\\\\ \n",
        "21 & 24 & 27\n",
        "\\end{pmatrix}.$$\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "mr50Ru_0IIJA"
      },
      "source": [
        "Так же это происходит и в Python:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "xki24ZZkIIJB",
        "outputId": "b50fa258-7735-4026-b366-a52f5727616c"
      },
      "source": [
        "a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])\n",
        "k = 3\n",
        "\n",
        "print(f'Матрица А\\n{a}\\n')\n",
        "print(f'Матрица 3*А\\n{k*a}')"
      ],
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Матрица А\n",
            "[[1 2 3]\n",
            " [4 5 6]\n",
            " [7 8 9]]\n",
            "\n",
            "Матрица 3*А\n",
            "[[ 3  6  9]\n",
            " [12 15 18]\n",
            " [21 24 27]]\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "0BaC3kiiIIJI"
      },
      "source": [
        "Умножение матрицы на число обладает следующими свойствами:<br>\n",
        "1) $(\\lambda \\mu)A=\\lambda(\\mu A);$<br>\n",
        "2) $\\lambda (A+B)=\\lambda A + \\lambda B;$<br>\n",
        "3) $(\\lambda + \\mu) A = \\lambda A + \\mu A.$"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Pvc1GxhLIIJM"
      },
      "source": [
        "### 3. Перемножение матриц"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Ncq5och4IIJO"
      },
      "source": [
        "_Произведением_ матрицы $A = \\left\\|a_{ij}\\right\\|$, имеющей порядки $m$ и $n$, и матрицы $B = \\left\\|b_{ij}\\right\\|$, имеющей порядки $n$ и $k$, называется матрица $C = \\left\\|c_{ij}\\right\\|$, имеющая порядки $m$ и $k$:\n",
        "\n",
        "$$C = \\begin{pmatrix}\n",
        "c_{11} & c_{12} & \\cdots & c_{1k}\\\\ \n",
        "c_{21} & c_{22} & \\cdots & c_{2k}\\\\ \n",
        "\\cdots & \\cdots & \\ddots & \\cdots\\\\ \n",
        "c_{m1} & c_{m2} & \\cdots & c_{mk}\n",
        "\\end{pmatrix},$$\n",
        "\n",
        "наполненная элементами, определяемыми формулой\n",
        "\n",
        "$$ c_{ij}=\\sum_{p=1}^{n}a_{ip}b_{pj}.$$"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ypjQS0x2IIJP"
      },
      "source": [
        "Правило перемножения матриц можно сформулировать словесно следующим образом: _элемент $c_{ij}$, стоящий на пересечении $i$-й строки и $j$-го столбца матрицы $C=A\\cdot B$, равен сумме попарных произведений соответствующих элементов $i$-й строки матрицы $A$ и $j$-го столбца матрицы $B$._"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "_A_6aH_YIIJQ"
      },
      "source": [
        "Следует заметить, что матрицу $A$ можно умножить не на всякую матрицу $B$: __необходимо, чтобы число столбцов матрицы $A$ было равно числу строк матрицы $B$.__"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "bG5ktORzIIJW"
      },
      "source": [
        "В частности, определить оба произведения $A\\cdot B$ и $B\\cdot A$ можно только в случае, когда число столбцов $A$ совпадает с числом строк $B$, а число строк $A$ совпадает с числом столбцов $B$. В этом случае матрицы $A\\cdot B$ и $B\\cdot A$ будут квадратными. Их порядок в общем случае будет различным и будет совпадать только в случае квадратных матриц $A$ и $B$."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "gEOYzBW5IIJY"
      },
      "source": [
        "__Пример 1__\n",
        "\n",
        "Скалярное произведение векторов, рассмотренное нами на предыдущем уроке, можно понимать как умножение вектора-строки на вектор-столбец."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "qduLuBSdIIJZ"
      },
      "source": [
        "__Пример 2__\n",
        "\n",
        "Для лучшего понимания рассмотрим в качестве примера перемножение квадратных матриц второго порядка:\n",
        "\n",
        "$$\\begin{pmatrix}\n",
        "a_{11} & a_{12}\\\\ \n",
        "a_{21} & a_{22}\n",
        "\\end{pmatrix} \\begin{pmatrix}\n",
        "b_{11} & b_{12}\\\\ \n",
        "b_{21} & b_{22}\n",
        "\\end{pmatrix}=\\begin{pmatrix}\n",
        "(a_{11}b_{11} + a_{12}b_{21}) & (a_{11}b_{12} + a_{12}b_{22})\\\\ \n",
        "(a_{21}b_{11} + a_{22}b_{21}) & (a_{21}b_{12} + a_{22}b_{22})\n",
        "\\end{pmatrix}.$$"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Kx83KwcAIIJa"
      },
      "source": [
        "__Пример 3__\n",
        "\n",
        "Перемножим матрицы \n",
        "\n",
        "$$A=\\begin{pmatrix}\n",
        "1 & 0\\\\ \n",
        "2 & 1\\\\ \n",
        "10 & 5\n",
        "\\end{pmatrix} \\; и \\; B=\\begin{pmatrix}\n",
        "2 & 0 & 0\\\\ \n",
        "0 & 0 & 1\n",
        "\\end{pmatrix}.$$\n",
        "\n",
        "$$A\\cdot B=\\begin{pmatrix}\n",
        "1\\cdot2+0\\cdot0 & 1\\cdot0+2\\cdot0 & 1\\cdot0+0\\cdot1\\\\ \n",
        "2\\cdot2+1\\cdot0 & 2\\cdot0+1\\cdot0 & 2\\cdot0+1\\cdot1\\\\ \n",
        "10\\cdot2+5\\cdot0 & 10\\cdot0+5\\cdot0 & 10\\cdot0+5\\cdot1\n",
        "\\end{pmatrix}=\\begin{pmatrix}\n",
        "2 & 0 & 0\\\\ \n",
        "4 & 0 & 1\\\\ \n",
        "20 & 0 & 5\n",
        "\\end{pmatrix}.$$"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "-gZBASdqIIJc"
      },
      "source": [
        "Сделаем то же самое при помощи Python.\n",
        "\n",
        "В библиотеке NumPy перемножение матриц осуществляется при помощи тех же инструментов, которые мы использовали для нахождения скалярного произведения векторов, — функции `numpy.dot(a, b)` или метода `a.dot(b)`, только в этом случае `a` и `b` — матрицы."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "byP9e5P6IIJe",
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "outputId": "1450af0c-095c-4cc9-d070-0dca13735ded"
      },
      "source": [
        "A = np.array([[1, 0], [2, 1], [10, 5]])\n",
        "B = np.array([[2, 0, 0], [0, 0, 1]])\n",
        "\n",
        "print(f'Матрица A\\n{A}')\n",
        "print(f'Матрица B\\n{B}')\n",
        "print(f'Матрица AB\\n{np.dot(A, B)}')"
      ],
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Матрица A\n",
            "[[ 1  0]\n",
            " [ 2  1]\n",
            " [10  5]]\n",
            "Матрица B\n",
            "[[2 0 0]\n",
            " [0 0 1]]\n",
            "Матрица AB\n",
            "[[ 2  0  0]\n",
            " [ 4  0  1]\n",
            " [20  0  5]]\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "LpkPfDRfIIJj"
      },
      "source": [
        "Попробуем перемножить матрицы, не отвечающие правилу соответствия количества строк и столбцов:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "aBFY1bykIIJk",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 367
        },
        "outputId": "d1e74833-ae28-4140-e8d0-d38757882e82"
      },
      "source": [
        "A = np.array([[1, 0], [2, 1], [10, 5]])\n",
        "B = np.array([[2, 0, 0], [0, 0, 1], [0, 0, 1]])\n",
        "\n",
        "print(f'Матрица A\\n{A}')\n",
        "print(f'Матрица B\\n{B}')\n",
        "print(f'Матрица AB\\n{np.dot(A, B)}')"
      ],
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Матрица A\n",
            "[[ 1  0]\n",
            " [ 2  1]\n",
            " [10  5]]\n",
            "Матрица B\n",
            "[[2 0 0]\n",
            " [0 0 1]\n",
            " [0 0 1]]\n"
          ],
          "name": "stdout"
        },
        {
          "output_type": "error",
          "ename": "ValueError",
          "evalue": "ignored",
          "traceback": [
            "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
            "\u001b[0;31mValueError\u001b[0m                                Traceback (most recent call last)",
            "\u001b[0;32m<ipython-input-3-c706fad344df>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      4\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mf'Матрица A\\n{A}'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      5\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mf'Матрица B\\n{B}'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 6\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mf'Матрица AB\\n{np.dot(A, B)}'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
            "\u001b[0;32m<__array_function__ internals>\u001b[0m in \u001b[0;36mdot\u001b[0;34m(*args, **kwargs)\u001b[0m\n",
            "\u001b[0;31mValueError\u001b[0m: shapes (3,2) and (3,3) not aligned: 2 (dim 1) != 3 (dim 0)"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "gbk1i4SqIIJq"
      },
      "source": [
        "Запуск кода в ячейке выше приводит к ошибке, так как количество столбцов первой матрицы не равно количеству строк второй при перемножении."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "qHsRShp0IIJr"
      },
      "source": [
        "__Пример 4__\n",
        "\n",
        "Перемножим матрицы\n",
        "\n",
        "$$A = \\begin{pmatrix}\n",
        "1 & 3\\\\ \n",
        "2 & 6\n",
        "\\end{pmatrix} ~ \n",
        "и ~\n",
        "B = \\begin{pmatrix}\n",
        "9 & 6\\\\ \n",
        "-3 & -2\n",
        "\\end{pmatrix}.$$\n",
        "\n",
        "$$\\begin{pmatrix}\n",
        "1 & 3\\\\ \n",
        "2 & 6\n",
        "\\end{pmatrix} \\cdot\n",
        "\\begin{pmatrix}\n",
        "9 & 6\\\\ \n",
        "-3 & -2\n",
        "\\end{pmatrix} = \n",
        "\\begin{pmatrix}\n",
        "1\\cdot 9 + 3\\cdot (-3) & 1\\cdot6 + 3\\cdot (-2)\\\\ \n",
        "2\\cdot 9 + 6\\cdot (-3) & 2\\cdot6 + 6\\cdot (-2)\n",
        "\\end{pmatrix} = \n",
        "\\begin{pmatrix}\n",
        "0 & 0\\\\ \n",
        "0 & 0\n",
        "\\end{pmatrix}.\n",
        "$$"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Jmgqr7OnIIJt"
      },
      "source": [
        "Это важный пример, показывающий наличие среди матриц делителей нуля, т. е. ненулевых матриц, при перемножении дающих _нулевую матрицу_."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Yg3_X_DMIIJu"
      },
      "source": [
        "Из специфики произведения матриц следует, что оно не обладает свойством коммутативности, то есть $AB\\neq BA$. В общем случае это справедливо даже для квадратных матриц, например:\n",
        "\n",
        "$$\\begin{pmatrix}\n",
        "0 & 0\\\\ \n",
        "0 & 1\n",
        "\\end{pmatrix} \\begin{pmatrix}\n",
        "0 & 0\\\\ \n",
        "1 & 0\n",
        "\\end{pmatrix}=\\begin{pmatrix}\n",
        "0 & 0\\\\ \n",
        "1 & 0\n",
        "\\end{pmatrix},$$\n",
        "$$\\begin{pmatrix}\n",
        "0 & 0\\\\ \n",
        "1 & 0\n",
        "\\end{pmatrix}\\begin{pmatrix}\n",
        "0 & 0\\\\ \n",
        "0 & 1\n",
        "\\end{pmatrix}=\\begin{pmatrix}\n",
        "0 & 0\\\\ \n",
        "0 & 0\n",
        "\\end{pmatrix}.$$\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "PhVfkiNRIIJw"
      },
      "source": [
        "Однако произведению матриц __подходящих размеров__ свойственны другие особенности:\n",
        "\n",
        "1. Ассоциативность: $(AB)C = A(BC).$\n",
        "\n",
        "   __Доказательство__\n",
        "\n",
        "    Возьмем матрицы $A$ размера $m\\times n$, $B$ размера $n\\times k$, $C$ размера $k\\times l$. Тогда, по определению $i,j$-й элемент произведения матрицы $AB$ на матрицу $C$ равен:\n",
        "\n",
        "$$\\{(AB)C\\}_{ij}=\\sum_{p=1}^{k}\\{AB\\}_{ip}c_{pj}=\\sum_{p=1}^{k}\\  \n",
        "(\\sum_{q=1}^{n}a_{iq}b_{qp})c_{pj}=\\sum_{q=1}^{n}a_{iq}(\\sum_{p=1}^{k}b_{qp}c_{pj})=\\{A(BC)\\}_{ij},\n",
        "$$\n",
        "\n",
        "    что и требовалось доказать.\n",
        "\n",
        "\n",
        "2. Дистрибутивность: $(A+B)C = AC + BC$ и $A(B+C) = AB + AC$.\n",
        "\n",
        "    Это свойство вытекает из определений суммы и произведения матриц."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "vym6VYYAIIJx"
      },
      "source": [
        "__Возведение матриц в степень__ является частным случаем перемножения:\n",
        "\n",
        "$$A\\cdot A = A^{2}.$$"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "2LMGVufIIIJy"
      },
      "source": [
        "__Пример__\n",
        "\n",
        "$$\\begin{pmatrix}\n",
        "1 & 1\\\\ \n",
        "0 & 1\n",
        "\\end{pmatrix}^{2} = \n",
        "\\begin{pmatrix}\n",
        "1 & 1\\\\ \n",
        "0 & 1\n",
        "\\end{pmatrix} \\cdot\n",
        "\\begin{pmatrix}\n",
        "1 & 1\\\\ \n",
        "0 & 1\n",
        "\\end{pmatrix} = \n",
        "\\begin{pmatrix}\n",
        "1\\cdot1 + 1\\cdot0 & 1\\cdot1 + 1\\cdot1\\\\ \n",
        "0\\cdot1 + 1\\cdot0 & 0\\cdot1 + 1\\cdot1\n",
        "\\end{pmatrix} = \n",
        "\\begin{pmatrix}\n",
        "1 & 2\\\\ \n",
        "0 & 1\n",
        "\\end{pmatrix}\n",
        "$$"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "YLI7KB2SIIJ0"
      },
      "source": [
        "### 4. Транспонирование матриц"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "nc7zPlUtIIJ2"
      },
      "source": [
        "Рассмотрим еще одну распространенную процедуру при работе с матрицами, называемую _транспонированием._"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ev5vUL01IIJ4"
      },
      "source": [
        "Пусть имеется матрица $A$ размера $m\\times n$. В таком случае матрица $B$, полученная транспонированием матрицы $A$ и обозначаемая $B=A^{T}$, будет представлять собой матрицу размера $n\\times m$, элементы которой $b_{ij}=a_{ji}$. Иными словами, транспонированная матрица — это матрица, отраженная относительно главной диагонали (диагональ, на которой распологаются элементы с $i=j$). При транспонировании строки исходной матрицы становятся столбцами, а столбцы — строками."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "-NVLs4OxIIJ5"
      },
      "source": [
        "__Пример__\n",
        "\n",
        "$$A=\\begin{pmatrix}\n",
        "8 & 5 & 3\\\\ \n",
        "4 & 6 & 1\\\\ \n",
        "0 & 11 & 9\\\\ \n",
        "2 & 7 & 10\n",
        "\\end{pmatrix}, \\;A^{T}=\\begin{pmatrix}\n",
        "8 & 4 & 0 & 2\\\\ \n",
        "5 & 6 & 11 & 7\\\\ \n",
        "3 & 1 & 9 & 10\n",
        "\\end{pmatrix}.$$"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "YW_5jcRVIIKJ"
      },
      "source": [
        "В NumPy транспонированная матрица вычисляется с помощью функции `numpy.transpose(array)` или с помощью метода `array.T`, где `array` — матрица."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "Df1BiA-LIIKK",
        "outputId": "57ceaab8-8ccb-45ed-847a-17a5fb26d97d"
      },
      "source": [
        "a = np.array([[8, 5, 3], [4, 6, 1], [0, 11, 9], [2, 7, 10]])\n",
        "\n",
        "print(f'Матрица:\\n{a}')\n",
        "print(f'Транспонированная матрица:\\n{a.T}')"
      ],
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Матрица:\n",
            "[[ 8  5  3]\n",
            " [ 4  6  1]\n",
            " [ 0 11  9]\n",
            " [ 2  7 10]]\n",
            "Транспонированная матрица:\n",
            "[[ 8  4  0  2]\n",
            " [ 5  6 11  7]\n",
            " [ 3  1  9 10]]\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "TeVOF0NvIILG"
      },
      "source": [
        "Некоторые важные свойства транспонирования:<br>\n",
        "1) $(A+B)^{T}=A^{T}+B^{T};$<br>\n",
        "2) $(A\\cdot B)^{T}=B^{T}\\cdot A^{T}.$"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "DxfSvwWmIILI"
      },
      "source": [
        "## Типы матриц"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "GL3clunBIILJ"
      },
      "source": [
        "Рассмотрим некоторые особые типы матриц, которые понадобятся нам в будущем, в частности, при рассмотрении темы линейных преобразований и матричных разложений."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "rG2vBZvHIILL"
      },
      "source": [
        "### Диагональная матрица"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "1WpriYv8IILM"
      },
      "source": [
        "_Диагональная матрица_ — матрица, в которой все элементы, не лежащие на главной диагонали, — нулевые:\n",
        "\n",
        "$$D = \\begin{pmatrix}\n",
        "d_{1} & 0 & \\cdots & 0\\\\ \n",
        "0 & d_{2} & \\cdots  & 0\\\\ \n",
        "\\cdots & \\cdots & \\ddots & \\cdots\\\\ \n",
        "0 & 0 & \\cdots & d_{n}\n",
        "\\end{pmatrix}.$$"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "v8ARmXZjIILO"
      },
      "source": [
        "Частным случаем диагональной матрицы является _единичная матрица_, обычно обозначаемая $E$ или $I$ — это матрица, в которой главную диагональ занимают единицы, а остальные элементы — нулевые:\n",
        "\n",
        "$$E=\\begin{pmatrix}\n",
        "1 & 0 & \\cdots & 0\\\\ \n",
        "0 & 1 & \\cdots  & 0\\\\ \n",
        "\\cdots & \\cdots & \\ddots & \\cdots\\\\ \n",
        "0 & 0 & \\cdots & 1\n",
        "\\end{pmatrix}.$$\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "O9GaXXjJIILP"
      },
      "source": [
        "В NumPy единичная матрица задается при помощи функции `numpy.eye(n)`, где `n` — порядок матрицы:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "OeWtn-CvIILQ",
        "outputId": "0cb38c34-90b5-4718-c6a3-53fe0d7c2bf3"
      },
      "source": [
        "e = np.eye(5)\n",
        "print(f'Единичная матрица:\\n{e}')"
      ],
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Единичная матрица:\n",
            "[[1. 0. 0. 0. 0.]\n",
            " [0. 1. 0. 0. 0.]\n",
            " [0. 0. 1. 0. 0.]\n",
            " [0. 0. 0. 1. 0.]\n",
            " [0. 0. 0. 0. 1.]]\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "V4pXpL7lIILX"
      },
      "source": [
        "### Треугольная матрица"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "PorbtHZUIILZ"
      },
      "source": [
        "_Треугольная матрица_ — квадратная матрица, у которой все элементы, стоящие ниже (или выше) главной диагонали — нулевые."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "wFa9I4LzIILb"
      },
      "source": [
        "Треугольная матрица, у которой все элементы ниже главной диагонали равны нулю, называется _верхней треугольной (верхне-треугольной)_ матрицей:\n",
        "\n",
        "$$\\begin{pmatrix}\n",
        "a_{11} & a_{12} & \\cdots & a_{1n}\\\\ \n",
        "0 & a_{22} & \\cdots & a_{2n}\\\\  \n",
        "\\cdots & \\cdots & \\ddots & \\cdots \\\\ \n",
        "0 & 0 & \\cdots & a_{nn}\\\\ \n",
        "\\end{pmatrix}.$$\n",
        "\n",
        "Треугольная матрица, у которой все элементы выше главной диагонали равны нулю, называется _нижней треугольной (нижне-треугольной)_ матрицей:\n",
        "\n",
        "$$\\begin{pmatrix}\n",
        "a_{11} & 0 & \\cdots & 0\\\\ \n",
        "a_{21} & a_{22} & \\cdots & 0\\\\  \n",
        "\\cdots & \\cdots & \\ddots & \\cdots \\\\ \n",
        "a_{n1} & a_{n2} & \\cdots & a_{nn}\\\\ \n",
        "\\end{pmatrix}.$$"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "yuBHV0THIILc"
      },
      "source": [
        "Важное свойство верхне-треугольных матриц: _при перемножении верхне-треугольных матриц свойство верхней треугольности сохраняется._"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "QthJnXTHIILd"
      },
      "source": [
        "__Пример__"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "AMhaFP0OIILe",
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "outputId": "7f12e2e0-6929-4017-dee0-db0becc1218a"
      },
      "source": [
        "import numpy as np\n",
        "a = np.array([[4, 5, 2], [1, -2, 3]])\n",
        "b = np.array([[4, 1], [5, -2], [2, 3]])\n",
        "\n",
        "print(f'Матрица A\\n{a}\\n')\n",
        "print(f'Матрица B\\n{b}\\n')\n",
        "print(f'Матрица AB\\n{np.dot(a, b)}')"
      ],
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Матрица A\n",
            "[[ 4  5  2]\n",
            " [ 1 -2  3]]\n",
            "\n",
            "Матрица B\n",
            "[[ 4  1]\n",
            " [ 5 -2]\n",
            " [ 2  3]]\n",
            "\n",
            "Матрица AB\n",
            "[[45  0]\n",
            " [ 0 14]]\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Nby-UpRiIILl"
      },
      "source": [
        "### Ортогональная матрица"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "2GmzUAPFIILm"
      },
      "source": [
        "Матрица $A$ называется _ортогональной_, если \n",
        "\n",
        "$$AA^{T}=A^{T}A=E.$$"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "2GEwHpHMIILn"
      },
      "source": [
        "__Пример__"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "5P430W3bIILo"
      },
      "source": [
        "Ортогональной является матрица\n",
        "\n",
        "$$\\begin{pmatrix}\n",
        "cos\\varphi & -sin\\varphi\\\\ \n",
        "sin \\varphi & cos\\varphi\n",
        "\\end{pmatrix}.$$"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "aaURChnLIILq"
      },
      "source": [
        "Убедимся, что это действительно так:\n",
        "\n",
        "$$\\begin{pmatrix}\n",
        "cos\\varphi & -sin\\varphi\\\\ \n",
        "sin \\varphi & cos\\varphi\n",
        "\\end{pmatrix} \\cdot \n",
        "\\begin{pmatrix}\n",
        "cos\\varphi & sin\\varphi\\\\ \n",
        "-sin \\varphi & cos\\varphi\n",
        "\\end{pmatrix} = \n",
        "\\begin{pmatrix}\n",
        "cos\\varphi \\cdot cos\\varphi + (-sin\\varphi) \\cdot (-sin\\varphi) & cos\\varphi \\cdot sin\\varphi + (-sin\\varphi) \\cdot cos\\varphi\\\\ \n",
        "sin\\varphi \\cdot cos\\varphi + cos\\varphi \\cdot (-sin\\varphi) & sin\\varphi \\cdot sin\\varphi + cos\\varphi \\cdot cos\\varphi\n",
        "\\end{pmatrix} = \n",
        "\\begin{pmatrix}\n",
        "1 & 0\\\\ \n",
        "0 & 1\n",
        "\\end{pmatrix}.$$"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "v-syO8J6IILr"
      },
      "source": [
        "### Симметричная матрица"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "F-cW8mZCIILv"
      },
      "source": [
        "Матрица $A$ называется _симметричной_, если\n",
        "\n",
        "$$A=A^{T},$$\n",
        "\n",
        "то есть симметричная матрица симметрична относительно главной диагонали."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "VAmOu--LIILw"
      },
      "source": [
        "## Практическое задание"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "APeDlmh8IIL1"
      },
      "source": [
        "Все задания рекомендуется делать вручную, затем проверяя полученные результаты с использованием numpy.\n",
        "\n",
        "__1.__ Установить, какие произведения матриц $AB$ и $BA$ определены, и найти размерности полученных матриц:\n",
        "\n",
        "   а) $A$ — матрица $4\\times 2$, $B$ — матрица $4\\times 2$;\n",
        "    \n",
        "   б) $A$ — матрица $2\\times 5$, $B$ — матрица $5\\times 3$;\n",
        "    \n",
        "   в) $A$ — матрица $8\\times 3$, $B$ — матрица $3\\times 8$;\n",
        "    \n",
        "   г) $A$ — квадратная матрица $4\\times 4$, $B$ — квадратная матрица $4\\times 4$.\n",
        "    \n",
        "__2.__ Найти сумму и произведение матриц $A=\\begin{pmatrix}\n",
        "1 & -2\\\\ \n",
        "3 & 0\n",
        "\\end{pmatrix}$ и $B=\\begin{pmatrix}\n",
        "4 & -1\\\\ \n",
        "0 & 5\n",
        "\\end{pmatrix}.$\n",
        "\n",
        "__3.__ Из закономерностей сложения и умножения матриц на число можно сделать вывод, что матрицы одного размера образуют линейное пространство. Вычислить линейную комбинацию $3A-2B+4C$ для матриц $A=\\begin{pmatrix}\n",
        "1 & 7\\\\ \n",
        "3 & -6\n",
        "\\end{pmatrix}$, $B=\\begin{pmatrix}\n",
        "0 & 5\\\\ \n",
        "2 & -1\n",
        "\\end{pmatrix}$, $C=\\begin{pmatrix}\n",
        "2 & -4\\\\ \n",
        "1 & 1\n",
        "\\end{pmatrix}.$\n",
        "    \n",
        "__4.__ Дана матрица $A=\\begin{pmatrix}\n",
        "4 & 1\\\\ \n",
        "5 & -2\\\\ \n",
        "2 & 3\n",
        "\\end{pmatrix}$.\n",
        "Вычислить $AA^{T}$ и $A^{T}A$.\n",
        "\n",
        "__5*.__ Написать на Python функцию для перемножения двух произвольных матриц, не используя NumPy."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Hf6DyIW7IIL2"
      },
      "source": [
        "## Литература"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "1o5ffOF1J8iy"
      },
      "source": [
        ""
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "7cL5CARGIIL6"
      },
      "source": [
        "1. Ильин В. А., Позняк Э. Г. Линейная алгебра: Учеб. для вузов. — 6-е изд. — М.: Физматлит, 2005.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "IqMIzV4blFj6"
      },
      "source": [
        ""
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Vb0b3GdZIIL7"
      },
      "source": [
        "## Дополнительные материалы"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "qtaxCeq1IIL8"
      },
      "source": [
        "1. [Способы задать матрицу в NumPy](https://docs.scipy.org/doc/numpy-1.10.1/user/basics.creation.html).\n",
        "2. [numpy.transpose](https://docs.scipy.org/doc/numpy-1.10.0/reference/generated/numpy.transpose.html).\n",
        "3. [array.T](https://docs.scipy.org/doc/numpy-1.10.0/reference/generated/numpy.ndarray.T.html).\n",
        "4. [Перемножение матриц в NumPy](https://docs.scipy.org/doc/numpy-1.10.0/reference/routines.linalg.html#matrix-and-vector-products)."
      ]
    }
  ]
}